/**
 * 读取本地文件流式上传 oss
 */
import { Request, Response } from "express";
import path from "path";
import { putBucket } from "../plugins/oss/bucket";
import client from "../plugins/oss/client";
import { unlinkSync } from "../plugins/oss/fs";

// 检查文件分片是否上传了
const headFile = async (ossPath: string = "", query: any = {}) => {
  const { index, chunkSize, uploadType = "" } = query;
  try {
    if (!ossPath || uploadType !== "start") return;

    // 文件存在时
    const data: any = await client.head(ossPath);
    const position = Number(
      data.res.headers["x-oss-next-append-position"] || 0
    );
    const uploadPosition = Number(index) * Number(chunkSize);
    if (uploadPosition < position) {
      return {
        isUpload: true,
        position, // position 告诉前端应该上传 position / chunkSize 位置的切片
        msg: "当前切片已上传",
      };
    } else if (uploadPosition > position + Number(chunkSize)) {
      return {
        isError: true,
        position, // position 告诉前端应该上传 position / chunkSize 位置的切片
        msg: "当前切片上传顺序异常",
      };
    } else {
      return {
        isOk: true,
        position, // position 告诉前端应该上传 position / chunkSize 位置的切片
        msg: "继续上传文件",
      };
    }
  } catch (err: any) {
    // Oss 不存在当前要上传的文件
    return {
      isOk: true,
      code: "NoSuchKey",
    };
  }
};

export default async (req: Request, res: Response) => {
  // 检查文件是否上传成功
  if (!req?.file) {
    res.status(400).send("No file uploaded");
  } else {
    try {
      const {
        groupId = "",
        fileId = "",
        name = "",
        index = 0,
        size = 0,
        chunkSize = 0,
        uploadType = "",
      } = req.body;
      const filename = (req.file as any).filename;

      // 本地文件地址
      const localPath = path.join(__dirname, "../../uploads", filename);

      // 上传文件到 Oss，上传成功返回信息
      const ossPath: string = `${groupId}/${fileId}${path.extname(name)}`;

      await putBucket();

      // 检查待上传文件在 OSS 的信息
      const fileInfo = await headFile(ossPath, {
        index,
        chunkSize,
        uploadType,
      });

      // 当前切片上传顺序异常 | 当前切片已上传 时，不在执行后续逻辑
      if (fileInfo?.isError || fileInfo?.isUpload) {
        // 删除本地临时文件
        unlinkSync(localPath);

        res.send({
          code: 0,
          data: {
            position: fileInfo.position,
          },
          msg: fileInfo.msg,
        });
        return;
      }

      // 将文件切片追加到 Oss 中对应的文件中
      const result = await client.append(ossPath, localPath, {
        position: Number(index) * Number(chunkSize) + "",
        meta: <any>{
          name,
          size,
          fileId,
          groupId,
        },
      });

      if (uploadType !== "end") {
        // 删除本地临时文件
        unlinkSync(localPath);

        res.send({
          code: 0,
          data: {
            position: (result.res.headers as any)["x-oss-next-append-position"],
          },
          msg: "分片上传成功",
        });
      } else {
        const OssFileInfo: any = await client.head(result.name);

        // 删除本地临时文件
        unlinkSync(localPath);

        res.send({
          code: 0,
          data: [
            {
              fileId: OssFileInfo.meta.fileid,
              groupId: OssFileInfo.meta.groupid,
              name: OssFileInfo.meta.name,
              createdTime: new Date(
                OssFileInfo.res.headers["last-modified"]
              ).getTime(),
              url: result.url,
            },
          ],
          msg: "文件上传成功",
        });
      }

      // res.send({
      //   ...result,
      // });
    } catch (err) {
      console.log("==================", err);
    }
  }
};
